using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Linq;

using SharpMUD.Framework.CorlibExtensions;

namespace SharpMUD.Framework.IO
{
    public class ByteQueueTextReader : TextReader
    {
        private Queue<byte> _ByteQueue;
        private System.Text.Encoding _TextEncoding;
        private string _NewLine;
        
        private ByteQueueTextReader() { }
        public ByteQueueTextReader(Queue<byte> byteQueue, System.Text.Encoding textEncoding)
        {
            this._ByteQueue = byteQueue;
            this._TextEncoding = textEncoding;
        }

        public override int Peek()
        {
            this.AttendPendingPossibleNewlinePart();
            this.AttendPossibleBackspaces();
            if (_ByteQueue.Count > 0)
                return (int)_ByteQueue.Peek();
            else
                return -1;
        }

        public override int Read()
        {
            this.AttendPendingPossibleNewlinePart();
            this.AttendPossibleBackspaces();
            if (_ByteQueue.Count > 0)
                return (int)_ByteQueue.Dequeue();
            else
                return -1;
        }

        public override string ReadToEnd()
        {
            this.AttendPendingPossibleNewlinePart();
            this.AttendPossibleBackspaces();
            return this.Encoding.GetString(this._ByteQueue.Dequeue(this._ByteQueue.Count));
        }

        public override string ReadLine()
        {
            this.AttendPendingPossibleNewlinePart();
            this.AttendPossibleBackspaces();
            if (this._ByteQueue.Count <= 0)
                return null;

            //    \r \n
            //    CR+LF
            //    0A 0D

            int byteCount = this._ByteQueue.Count;
            string buffer = this.Encoding.GetString(this._ByteQueue.Peek(byteCount));
            int x = 0;
            for (x = 0; x < byteCount; x++)
            {
                if (buffer[x] == '\r' || buffer[x] == '\n')
                {
                    _CachedNewlinePart = buffer[x];
                    break;
                }
            }
            if (_CachedNewlinePart == '\0')
                return null;
            else
            {
                string rslt = this.Encoding.GetString(this._ByteQueue.Dequeue(x));
                _ByteQueue.Dequeue();
                this.AttendPendingPossibleNewlinePart();
                return rslt;
            }
        }

        private char _CachedNewlinePart;
        public void AttendPendingPossibleNewlinePart()
        {
            if(this._ByteQueue.Count==0)
                return;
            if (_CachedNewlinePart == '\0')
                return;

            char pendingChar = (char)this.Encoding.GetChars(this._ByteQueue.Peek(1)).GetValue(0);
            if ((_CachedNewlinePart!='\0')               && 
                (pendingChar=='\r' || pendingChar=='\n') &&
                (_CachedNewlinePart!=pendingChar)    )
            {
                this._ByteQueue.Dequeue();
                this._NewLine = _CachedNewlinePart.ToString() + pendingChar.ToString();
                this._CachedNewlinePart = '\0';
                return;
            }
            else if (_CachedNewlinePart != '\0')
            {
                this._CachedNewlinePart = '\0';
                return;
            }
        }

        private void AttendPossibleBackspaces()
        {
            if (this._ByteQueue.Count <= 0)
                return;
            lock (this._ByteQueue)
            {
                int deletesAdded = 0;
                for (int x = (this._ByteQueue.Count - 1); x >= 0; x--)
                {
                    if (System.Convert.ToChar((int)this._ByteQueue.GetValue(x)) == '\b')
                    {
                        deletesAdded++;
                        this._ByteQueue.RemoveAt(x);
                    }
                    else
                    {
                        if (deletesAdded > 0)
                        {
                            this._ByteQueue.RemoveAt(x);
                            deletesAdded--;
                        }
                    }
                }
            }
        }

        public System.Text.Encoding Encoding
        {
            get
            {
                return this._TextEncoding;
            }
        }
    }
}
